package demo.message;

import demo.core.RaftNode;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 内存中的Raft消息处理器实现
 * 
 * <p>用于同一个JVM中的节点间通信测试，通过内存中的节点注册表直接调用目标节点的方法。
 * 这种实现避免了网络通信的复杂性，非常适合用于：</p>
 * <ul>
 *   <li>单元测试和集成测试</li>
 *   <li>Raft算法的验证和演示</li>
 *   <li>性能基准测试（排除网络因素）</li>
 * </ul>
 * 
 * <p><b>特性：</b></p>
 * <ul>
 *   <li>零延迟：消息传递没有网络延迟</li>
 *   <li>高可靠：没有网络丢包或分区</li>
 *   <li>线程安全：使用ConcurrentHashMap保证并发安全</li>
 *   <li>简单配置：通过静态方法管理节点注册</li>
 * </ul>
 * 
 * <p><b>使用模式：</b></p>
 * <pre>
 * // 创建节点
 * RaftNode node1 = new RaftNode("node1", peers, new InMemoryMessageHandler());
 * 
 * // 注册节点
 * InMemoryMessageHandler.registerNode("node1", node1);
 * 
 * // 测试完毕后清理
 * InMemoryMessageHandler.unregisterNode("node1");
 * </pre>
 * 
 * @author Raft Implementation Team
 * @version 1.0
 * @since 1.0
 */
public class InMemoryMessageHandler implements RaftMessageHandler {
    
    /** 节点注册表：nodeId -> RaftNode 的映射 */
    private static final Map<String, RaftNode> nodes = new ConcurrentHashMap<>();
    
    /**
     * 注册节点到内存注册表
     * 
     * <p>必须在节点创建后立即调用此方法，否则其他节点无法与此节点通信。</p>
     * 
     * @param nodeId 节点ID，不能为null或空
     * @param node 节点实例，不能为null
     * @throws IllegalArgumentException 如果参数不合法
     */
    public static void registerNode(String nodeId, RaftNode node) {
        if (nodeId == null || nodeId.trim().isEmpty()) {
            throw new IllegalArgumentException("节点ID不能为空");
        }
        if (node == null) {
            throw new IllegalArgumentException("节点实例不能为null");
        }
        
        nodes.put(nodeId, node);
        System.out.println("节点 " + nodeId + " 已注册到消息处理器");
    }
    
    /**
     * 从内存注册表中取消注册节点
     * 
     * <p>通常在节点关闭或测试清理时调用。</p>
     * 
     * @param nodeId 要取消注册的节点ID
     */
    public static void unregisterNode(String nodeId) {
        nodes.remove(nodeId);
        System.out.println("节点 " + nodeId + " 已从消息处理器注销");
    }
    
    /**
     * 获取当前注册的节点数量
     * 
     * @return 已注册的节点数量
     */
    public static int getRegisteredNodeCount() {
        return nodes.size();
    }
    
    /**
     * 检查节点是否已注册
     * 
     * @param nodeId 节点ID
     * @return 如果节点已注册返回true，否则返回false
     */
    public static boolean isNodeRegistered(String nodeId) {
        return nodes.containsKey(nodeId);
    }
    
    /**
     * 发送投票请求到目标节点
     * 
     * <p>通过内存注册表查找目标节点，直接调用其handleVoteRequest方法。</p>
     * 
     * @param targetNodeId 目标节点ID
     * @param request 投票请求消息
     * @return 投票响应；如果目标节点未注册或处理异常，返回拒绝投票的响应
     */
    @Override
    public RaftMessage.VoteResponse sendVoteRequest(String targetNodeId, RaftMessage.VoteRequest request) {
        RaftNode targetNode = nodes.get(targetNodeId);
        if (targetNode != null) {
            System.out.println("发送投票请求：" + request.getCandidateId() + " -> " + targetNodeId);
            return targetNode.handleVoteRequest(request);
        }
        return null;
    }

    /**
     * 发送附加日志请求到目标节点
     * 
     * <p>通过内存注册表查找目标节点，直接调用其handleAppendEntries方法。</p>
     * 
     * @param targetNodeId 目标节点ID
     * @param request 附加日志请求消息
     * @return 附加日志响应；如果目标节点未注册或处理异常，返回失败响应
     */
    @Override
    public RaftMessage.AppendEntriesResponse sendAppendEntries(String targetNodeId, RaftMessage.AppendEntriesRequest request) {
        RaftNode targetNode = nodes.get(targetNodeId);
        if (targetNode != null) {
            System.out.println("发送日志条目：" + request.getLeaderId() + " -> " + targetNodeId);
            return targetNode.handleAppendEntries(request);
        }
        return null;
    }
}